/----------------------------------------------------------------------------\
|-[ 06 ]----[ Curso de UNIX VI ]----[ Bajo ]---------------------------------|
\-------------------------------------------------------------------[ Ripe ]-/


Sexta entrega ya.... bufff. Bueno a mi opinion demasiadas para explicar el
funcionamiento basico de un sistema operativo, por lo que tratare de poner
la quinta y pisar a fondo el acelerador.

Que vamos a ver en esta sexta entrega? Pues vamos a explorar las
variables de entorno, veremos algunos metacaracteres que tenemos
pendientes, veremos alguna cosilla sobre los procesos, y haremos nuestro
primer shellscript (quiza me deje alguna cosa :P).

Partire de la base de que todos sabeis que es una variable (si no sabes
que es una variable que haces lellendo esto? deberias estar lellendo las
recetas de Carlos Argiano). Cuando hablamos de las variables de entorno
hablamos de una serie de variables que le indican algo al sistema,
logicamente el valor de estas variables puede ser modificado (por algo son
variables, de variar :P), pero estos cambios solo afectaran a la sesion
actual. 

NOTA: Si no recuerdo mal ya hemos tratado las variables (que no eran las
      de entorno) en una ocasion, cuando hablabamos de la orden "cd"... 
      que tiempos aquellos :P

Seguidamente paso a comentar las variables de entorno mas comunes (orden
alfavetico y tal).

1.- EUID: Es un numero que identifica los privilegios con los que se esta
          ejecutando el shell.

2.-HISTFILE: Path o ruta del fichero en el que se almacenara el historial
             de los comandos ejecutado.

3.-HOME: Path o ruta de entrada del usuario que esta usando elshell. 
         Cuando usamos "cd" sin argumento realmente estamos haciendo un
         "cd $HOME". (tambien representable como ~)

4.-HOSTNAME: Nombre de la maquina.

5.-HOSTTYPE: El tipo de procesador sobre el que corre la maquina.

6.-IFS: Separador de campo interno, sirve para que el shell interprete las
        lineas como elemetos separados... es algo chungo de explicar, pero
        muy util a la hora de programar ciertos scripts (lo veremos).

7.-MAIL: Path o ruta del fichero en el que se guarda el correo recibido
         por el usuario.

8.-MAILCHECK: Intervalo de tiempo en el que el sistema comprueba si el
              usuario tiene nuevo correo.

9.-OLDPWD: Path o ruta del directorio anterior al que se encontraba el
           usuario anteriormente al actual. (tambien representable como -)

10.-PATH: Importante variable de entorno que contiene muchas rutas
          separadas por ":". Cuando un usuario introduce una orden en la
          linea de comandos, el shell busca en los directorios de la
          variable PATH un ejecutable con el nombre indicado y lo ejecuta
          si el usuario tiene los privilegios apropiados.

11.-PPID: Pid del shell (kill -9 $PPID # O:->)

12.-PS1: Contiene el prompt principal.

13.-PS2: Contiene el prompt secubario.

14.-PWD: Path o ruta del directorio de trabajo actual.

15.-SHELL: Path o ruta del ejecutable que carago el shell.

16.-TERM: Tipo de terminal.

17.-UID: Numero que identifica los privilegios del usuario que cargo el
         shell.

18.-USER: Usuario actual.

19.-USERNAME: Usuario que cargo el shell.

Es *MUY* posible que me haya olvidado de alguna variable de entorno de
echo si haceis un "set | more" vereis muchas mas.... investigad y tratad
de averiguar lo que quieren decir :P

Si has leido todos los numero del curso de UNIX habras aprendido que los
metacaracteres son realmente utiles y que permiten ahorar mucho trabajo, por
ello se pueden encontrar metacaracteres de todo tipo. Vamos a ver.

------------------------------------------------------------------------------
|                                                                            |
|       $ echo hola > hola.txt                                               |
|       $                                                                    |
|                                                                            |
------------------------------------------------------------------------------

Como es posible? He ejecutado un "echo hola" pero no se ha imprimido nada en
pantalla.... porque? Seguramente ya habras deducido el motivo: UNIX trata
todos los canale de entrada y salida como decrtiptores de fichero, de manera
que el decriptor de fichero "stdout" es el dispositivo standard de salida,
la pantalla. Lo que el metacaracter ">" hace es obligar a "echo" a usar un
decriptor de fichero que escriba en hola.txt en ve de usar "stdout". Vamos
a comprobarlo.

------------------------------------------------------------------------------
|                                                                            |
|       $ cat hola.txt                                                       |
|       hola                                                                 |
|       $                                                                    |
|                                                                            |
------------------------------------------------------------------------------

Iep! Mira donde habia ido a parar el "hola" escrito por echo... :) Bueno
ya te haces una idea de como funciona esto no? vamos a ver como se usa el
metacaracter ">" exactamente.

                          [num]>[>]

Ostia que lio.... Que es eso de num? Sencillo, si tu no quieres
redireccionar el decriptor "stdout" y quieres redireccionar el decriptor de
los mensajes de error deberas usar "2>". Y el ">" que hay detras? Tambien
sencillo. Cuando tu redireccionas hacia un fichero al scribir en el este se
trunca a 0 (se borra todo su contenido) si lo que queremos es conservar lo
que ya se encuentra escrito al fichero y aladirle al final lo que se ha
redireccionado deberas aadir un ">" adicional. Veamos.


------------------------------------------------------------------------------
|                                                                            |
|       $ echo adios > hola.txt                                              |
|       $ cat hola.txt                                                       |
|       adios                                                                |
|       $ echo linux tha best >> hola.txt                                    |
|       $ cat hola.txt                                                       |
|       adios                                                                |
|       linux tha best                                                       |
|       $                                                                    |
|                                                                            |
------------------------------------------------------------------------------

Pero no acaba aqui la potencia de este metacaracter.... recordad que UNIX
trata los dispositivos como ficheros, asi pues si /dev/lp0 es el
dispositivo en el que se encuentra la impresora y escribes "echo habia una
vez > /dev/lp0" lo que estaras haciendo es imprimir esa cadena de texto,
intresante no?

Pues tampoco acaba ahi.... Hay otro decriptor muy similiar que permite
redireccionar "stdin" el decriptor de fichero de la entrada standard
(normalmente el teclado). Creo que no hace falta que lo explique muy a fondo,
asi o dejo el gusanillo y experimentais vosotros que es como mejor se aprende
esto.

Hemos visto como redireccionar de un proceso a un fichero, pero tambien es
posible redireccionar de un proceso a otro proceso Como? Con un
metacaracter, como no :P Cual? El metacaracter "|". Tampoco voy explicarlo
muy a fondo, basta con que veais un ejemplo.

------------------------------------------------------------------------------
|                                                                            |
|       $ cat file1.txt                                                      |
|       Nombre          Tipo            Valor                                |
|       ------          ----            -----                                |
|       host1           3               mail                                 |
|       ret             1               12                                   |
|       autoread        2               off                                  |
|       getin           2               off                                  |
|       pass            3               miZr@@b!                             |
|       users_limit     1               300                                  |
|       $ cat file1.txt | grep 3                                             |
|       host1           3               mail                                 |
|       pass            3               miZr@@b!                             |
|       users_limit     1               300                                  |
|                                                                            |
------------------------------------------------------------------------------

Bueno, creo que a llegado la hora de atacar los procesos en sistemas UNIX,
no voy a hablar de ellos a bajo nivel (ni planificacion de procesos, ni
IPC, ni multiprogramacion.....), aunque es posible que para mas adelante
veais algo de todo esto por aqui.

Un proceso no es mas que un programa en ejecucion. Si yo ejecuto "ls
-l" estoy creando un proceso (aunque que este no durara demasiado). Los
sistemas UNIX, como ya dijimo, suelen ser multitarea, lo que quiere decir
que se pueden encontrar muchos procesos ejecutandose simultaneamente. Hay 
dibersas maneras de visualizarlos... Veamos algunas de ellas.

La visualizacion tipica (o almenos la mas usada) se realiza con "ps". Este
programa consta de muchas posiblidades, por lo que os animo a leer la
pagina man si quereis mas detalles, yo simplemente comentare lo que YO mas
uso, y esto es "ps -aux". El parametro "-a" hace que se muestren los
procesos de todos los usuarios del sistema, y no solo los tuyos. El
parametro "-u" sirve para darle a la salida el formato que veras a
continuacion. Y "-x" mustra los procesos que no son hijos de ningun
terminal. Veamos ahora mismo como esta mi maquina :P

------------------------------------------------------------------------------
|	                                                                     |
|	$ ps -aux                                                            |	
|	USER  PID  %CPU %MEM  VSZ  RSS TTY  STAT  START  TIME  COMMAND       |
|       root    1   0.2  1.5 1120  476  ?      S  12:22  0:05  init[3]       |
|       root    2   0.0  0.0    0    0  ?     SW  12:22  0:00  [kflushd]     |
|       root    3   0.0  0.0    0    0  ?     SW  12:22  0:00  [kupdate]     |
|       root    4   0.0  0.0    0    0  ?     SW  12:22  0:00  [kpiod]       |
|       root    5   0.0  0.0    0    0  ?     SW  12:22  0:00  [kswapd]      |
|       root    6   0.0  0.0    0    0  ?    SW<  12:22  0:00  [mdrecoveryd] |
|       root  240   0.0  1.5  1104  476 ?      S  12:22   0:00 /usr/sbin/apmd|
|                        <<<  Y muchos mas procesos  >>>                     |
|       $                                                                    |
|                                                                            |
------------------------------------------------------------------------------

Bien voy a comentar, de esta salida, las columnas que no esncontramos. USER
es la que indica el usuario que lanzo el proceso, PID es un numero que 
identifica a cada proceso, no puede haber 2 procesos con el mismo PID (veremos
mas adelante que el PID no sirbe para mandar signals a los procesos), %CPU
muestra el procentaje de uso de la CPU (en teoria la suma de todos los
porcentajes deberia llegar al 100%, pero nunca es asi, mecachis), %MEM indica
el procentaje de memoria utilizada, TTY muestra el terminal desde el que se ha
cargado el proceso (si hay un interrogante es que no se ha cargado desde
ningun terminal), STAT muetra las flags de estado, START el momento en que
se incio el proceso, TIME el tiempo asignado a la ejecucion, y COMMANDO pues
el comando que se uso para cargar el proceso.

En UNIX todo proceso tiene un padre (exepto init, pues es el primer proceso
en ejecutarse), lo que quiere decir que todo proceso esta llamado desde
otro proceso. Esto nos lleva a la idea de arbol de procesos, este arbol,
podriamos decir, es el arbol genealogico de una familia (Gustabo Proceso, es
hijo de Jesus Proceso). Para visualizar ese arbol se usa el comando "pstree".

------------------------------------------------------------------------------
|                                                                            |
|	$ pstree                                                             |
|       init-+-apmd                                                          |
|            |-gpm                                                           |
|            |-kflushd                                                       |
|            |-klogd                                                         |
|            |-kpiod                                                         |
|            |-kswapd                                                        |
|            |-kupdate                                                       |
|            |-login---bash---vi                                             |
|            |-login---bash---pstree                                         |
|            |-mdrecoveryd                                                   |
|            |-4*[mingetty]                                                  |
|            |-syslogd                                                       |
|            `-xfs                                                           |
|	$                                                                    |
|                                                                            |
------------------------------------------------------------------------------

NOTA: Como se ve claramente en este ejemplo, todos los procesos exepto init
      son hijos de algun proceso.

NOTA: "pstree" ofrece mas posiblidades. Para mas informacion recomiendo la
      visualizacion de la pagina man de pstree. "man pstree" ;)

Hemos visto que a cada proceso se le asocia un numerito, y que este recibe el
nombre de PID, ahora veremos como usar ese numero para mandar seales a los
procesos, de manera que podemos hacer, por ejemplo, que un proceso muera
repentinamente. 

Para mandar una seal a un proceso usaremos la orden kill. Su uso, basicamente,
es el siguiente "kill [-<numero de seal>] <numero de PID>", si no 
especificamos el numero de seal, kill tomara por defecto el 15.

Vaya estoy hablando de signals y aun no he dicho para que sirve cada uno... 
Pues pongamoles remedio :)

SIGHUP (1)     El sistema lo envia cuando el sistema detecta que muere el 
               proceso de control. Si ocurre esto el proceso termina (*).

SIGINT (2)     Se envia a todo proceso que se este ejecutando en un mismo 
               terminal de control. Si ocurre finaliza la ejecucion del 
               proceso que lo recibe (*).

SIGQUIT (3)    Finaliza el proceso al pulsar la tecla de salida. Por defecto
               genera un core (no te preocupes por esto del core ahora) y 
               finaliza la ejecucion (*).

SIGILL (4)     Se produce cuando un proceso intenta ejecutar ejecutar una
               instruccion ilegal. Su accion es la de generar un core y 
               terminar el proceso (*).

SIGTRAP (5)    Si se ejecuta un proceso "paso a paso" esta seal se envia 
               despues de cada instruccion.

SIGIOT (6)     Debido a un fallo de harware producido por otra maquina el
               proceso finaliza (*).

SIGEMT (7)     Signal poco utilizado que se usa tambien para indicar fallos de
               hardware. Su accion por defecto es generar el core y salir (*).

SIGFPE (8)     Error matematico en una operacion con coma flotante. Genera
               core y finaliza (*).

SIGKILL (9)    Esta seal proboca la immediata finalizacion de un proceso. 

SIGBUS (10)    Se produce cuando se da un error de acceso a memoria su accion?
               core y end :) (*).

SIGSEGV (11)   Se produce cuando un programa intenta acceder a memoria que
               no le perten (os suena de algo "Segmentation fault (core 
               dumped)" :P). Genera fichero core y finaliza (*).

SIGSYS (12)    Call erronea, posiblemente por que se le ha pasado mal un
               argumento (*).

SIGPIPE (13)   Se produce cuando se rompe un pipeline (tuberia). Se finaliza
               el proceso (*).

SIGALRM (14)   Se envia cuando alguno de los temporizadores del proceso llega
               a 0. Termina la ejecucion del proceso (*).

SIGTERM (15)   Finaliza un proceso de forma controlada, a diferencia de 
               SIGKILL su accion puede ser modificada, lo que hace que sea
               posible, para el programador, realizar una gestion rutinaria
               antes de finalizar la ejecucion (como por ejemplo cerrar
               ficheros, sockets, y llamar a exit()). Este es el signal que
               "kill" envia por defecto, y es tambien el que se manda a 
               todos los procesos en la intruccion "shutdown" (*).

SIGUSR1 (16)   Signal de usuario, la cual cosa quiere decir que esta reservada
               para el programador. Cada uno puede hacer lo que quiera con esta
               seal (*).

SIGUSER (17)   Mas de lo mismo (*).

SIGCLD (18)    Cuando un proceso hijo termina, manda esta seal al proceso
               padre (*).

SIGPWR (19)    Dependiendo de la maquina con la que tratemos puede tener 
               interpretaciones totalmente distintas. Una de ellas es una caida 
               iminente del sistema. Y la otra una recuperacion del sistema
               ante una situacion adversa (*).

SIGVTALARM (20) Indica que un temporizador virtual de proceso ha llegado a 0.
                Su accion por defecto es finalizar la ejecucion del proceso
                (*).

SIGPROF (21)   Un temporizador real y virtual ha llegado a 0 y se finaliza la
               ejecucion del proceso (*).

SIGIO (22)     Se envia cuando un dispositivo esta listo para operaciones de
               Entrada/Salida (*).

SIGWINCH (23)  Se usa unicamente en las sesiones X-Window para indicar que el
               tamao de una ventana ha cambiado (*).

SIGSTOP (24)   Finaliza el prceso de forma muy simiral al signal 9.

SIGTSTP (25)   Al igual que el siganl 15 finaliza el proceso de forma 
               controlada (*).

SIGCONT (26)   Esta seal se envia para reanudar la ejecucion de un proceso 
               (*).

SIGTTIN (27)   Cuando un proceso ejecutado en background intenta leer 
               del terminal de proceaso se envia esta seal, cuya accion por
               defecto es finalizar la ejecucion del proceso (*).

SIGTTOUT (28)  Lo mismo que el anterior, pero al intentar escribir (*) ;->

SIGURG (29)    Indica la llegada de un dato urgente por un canal de E/S (*).


NOTA: Muchos sistemas no implementan los signals del 20 al 29, por lo que es
      probable que en alguna maquina no os funcionen.

NOTA: De momemto dejamos aqui los procesos en UNIX, es muy probable que mas
      adelante, cuando ya tengamos una base en la programacion de sistemas 
      UNIX le dedique un amplio articulo a los procesos (signals, privilegios,
      IPC....).


Que mas dije que trataria? Ah! si, nuestro primer Shell-script :)

En muchas ocasiones, el usuario de un sistema UNIX ve que necesita realizar
una operacion en repetidas ocasiones, para ello el Shell del sistema UNIX 
dispone de un sistema de E/S que permite desaroyar scripts con las 
instrucciones del shell. Veamos, para empezar, un ejemplo sencillo de
shell-script.

------------------------------------------------------------------------------
|                                                                            |
|       $ cat myfirst.sh                                                     |
|       #!/bin/sh                                                            |
|       #                                                                    |
|       # Mi primer Shell-Script :)                                          |
|       #                                                                    |
|       FRASE="Hola mundo"                                                   |
|       echo $FRASE                                                          |
|       echo $FRASE > frase.txt                                              |
|       $ ./myfirst.sh                                                       |
|       Hola mundo                                                           |
|       $ cat frase.txt                                                      |
|       Hola mundo                                                           |
|       $                                                                    |
|                                                                            |
------------------------------------------------------------------------------

Se ve claramente lo que este mini-script realiza, imprime por pantalla "Hola
mundo", trunca a 0 el fichero frase.txt, e imprimer en su interior, de nuevo la
frase "Hola mundo". No creo que este shell-script necesite mucha mas
explicacion.

Vemos que la programacion de script puede ser muy util a la hora de
automatizar taread... Pero no seria mucho mas flexible si ademas
se puedieran usar condicionales, bucles & cia? Pues si, lo seria, y es por eso
que los desaroyadores de shells se encargan de que se disponga de esas
cosas, tan utiles en la programacion structurada :)

Empezaremos por ver el uso de los condicionales, veremos que no difiere mucho
de otros lenguajes de script.

	if [ condicion ]
        then
        <instrucciones>
        else
        <instrucciones>
        fi

Esto hara que se ejecuten las intrucciones que hay entre "then" y "else" si
la condicion es verdadera, y que se ejecuten las instrucciones entre "else" y
"fi" si, por el contario, es falsa. Obiamente no es obligatorio usar else,
como podemos ver:

	if [ condicion ]
        then
        <instrucciones>
        fi

En este caso las instrucciones alladas entre "then" y "fi" se ejecutarn siempre
y cuando la condicion sea verdadera.

Ademas en los shells-script, disponemos de "elif", un alias de "else if", y que
muy pocos lenguajes de programacion disponen entre sus erramientas, su uso
es el siguiente.

	if [ condicion 1 ]
        then
        <instrucciones>
        elif [ condicion 2 ]
        then
        <instrucciones>
        elif [ condicion 3 ]
        then
        <instrucciones>
        else
        <instrucciones>
        fi

Esto seria lo mismo que....

        if [ condicion 1 ]
        then
        <instrucciones>
        else
        if [ condicion 2 ]
        then
        <instrucciones>
        else 
        if [ condicion 3 ]
        then
        <instrucciones>
        else
        <instrucciones>
        fi
        fi
        fi

El ahorro de lineas de codigo es notable, por lo que es muy recomendable el 
uso de "elif" siempre que sea posible.

En el campo coindicion, podran ir dos valores, o 0 o 1, de menera que 0
infica falso y uno verdaro, si nosotros ponemos "if [ 1 ]", las condicion
sera siempre cierta, por lo contrario si ponemos "if [ 0 ]" sera siempre
falsa. 

En Shell-script se dispone de una instruucion evaluadora de coindiciones, esta
es "test", y permite comparar tanto numeros como cadenas de textom, ademas de 
realizar comprobaciones sobre ficheros. "test" devolvera 0 en caso de que la 
instruccion sea falsa y 1 en el caso de que sea cierta. El uso de esta 
instruccion es la siguiente.

	test [<expresion 1>] <operador> <expresion 2>

El <operador> tendra diferente simbologia si tratamos con numeros o con cadenas
de texto. Veamos a continuacion el uso de "test" con valores numericos.

  Operador        Uso           Ejemplo        Explicacion
  ~~~~~~~~        ~~~           ~~~~~~~        ~~~~~~~~~~~
    -eq       num1 -ep num2     6 -ep 20       Devuelve 1 en caso de que "num1"
                                               y "num2" sean iguales.

    -ne       num1 -ne num2     18 -ne 6       Devuelve 1 en el caso de que
                                               "num1" y "num2" sean diferentes.

    -gt       num1 -gt num2     1 -gt 2        Si "num1" es mayor que "num2"
                                               devolvera 1.

    -ge       num1 -ge num2     12 -ge 5       Devuelve 1 si "num1" es mayor o
                                               igual que "num2".

    -lt       num1 -lt num2     3 -lt 134      Retorna 1 en caso de que "num1"
                                               sea menor que "num2".
  
    -le       num1 -le num2     5 -le 23       Si "num1" es menor o igual que
                                               "num2" devuelve 1.

Vemos que las operaciones de comparacion numericas son muy distintas a como
suelen serlo en otros lenguajes de programacion. A mi, personalmente, no me
gusta esta faceta del shell-script.

Como he dicho, "test" puede usarse, ademas de para comparar valores numericos,
para comparar cadenas de texto, ello se realiza con los operadores que veremos
a continuacion.

  Operador        Uso           Ejemplo        Explicacion
  ~~~~~~~~        ~~~           ~~~~~~~        ~~~~~~~~~~~
     =        cad1 = cad2     "ho" = "jeje"    Devuelve 1 en caso de que ambas
                                               cadenas coincidan.
    
    !=        cad1 != cad2  "tigre" = "leon"   Devuelve 1 si "cad1" y "cad2"
                                               son distintas.

    -n           -n cad        -n "hola"       Devuelve 1 en caso de que la
                                               longitud de la cadena contenga
                                               caracteres.

    -z           -z cad        -z "xD"         En el caso de que la cadena sea
                                               nula devolvera 1.         
 

Y ahora veamos como nos permite "test" saber ciertas propiedades de un fichero,
cosa muy util a la hora de tratar con ellos.

  Operador        Uso           Ejemplo        Explicacion
  ~~~~~~~~        ~~~           ~~~~~~~        ~~~~~~~~~~~
    -r          -r file     -r /etc/shadow     Devuelve 1 en caso de que el
                                               fichero exista y pueda ser 
                                               leido.

    -w          -w file     -w /bin/login      Devuelve 1 en caso de que el
                                               fichero en cuestio, exista y
                                               pueda ser modificado.

    -s          -s file     -s /etc/securetty  Si el fichero tiene longitud
                                               nula, devuelve 1.

    -f          -f file     -f /etc            Devuelve 1 en el caso de que
                                               "file" sea un fichero 
                                               ordinario.

    -d          -d          -d /usr            Si el "file" es un directorio
                                               devolvera 1.
                                          
Bueno, acto seguido haremos tres scripts que nos premitiran ejemplificar como 
funciona todo esto :)

---/ ej1.sh /---

#!/bin/sh
#
# Lee dos valores, y realiza comparaciones.
#
echo "Introduce el valor de A:" 
read num1
echo "Introduce el valor de B:"
read num2
if test "$num1" -eq "$num2"
then
  echo "Los numeros A y B son el mismo numero"
else
  echo "Los numeros A y B son distintos"
  if test "$num1" -gt "$num2"
  then 
    echo "  A es mayor que B"
  else
    echo "  B es mayor que A"
  fi
fi
exit 0

---/ ej1.sh /---

---/ ej2.sh /---

#!/bin/sh
#
# Lee dos cadenas de texto, y las compara.
#
echo "Introduce la cadena A:"
read cad1
echo "Introduce la codena B:"
read cad2
if test -z "$cad1"
then
  echo "La cadena A es una cadena nula"
  exit 0
fi
if test -z "$cad2"
then
  echo "La cadena B es una cadena nula"
  exit 0
fi
if test "$cad1" = "$cad2"
then
  echo "Las dos cadenas son iguales"
else
  echo "Las dos cadenas son distintas"
fi
exit 0

---/ ej2.sh /---

---/ ej3.sh /---

#!/bin/sh
#
# Realiza un control de seguridad sobre los ficheros de contrasea del
# sistema.
#
PASSWD="/etc/passwd"
SHADOW="/etc/shadow"
SEGURO=1
echo "Iniciando rutina de control de seguridad..."
if test -w "$PASSWD"
then
  SEGURO=0
  echo "El usuario $USER puede escribir en $PASSWD"
fi
if test -r "$SHADOW"
then
  SEGURO=0
  echo "El usuario $USER puede leer en $SHADOW"
fi
if test "$SEGURO" -eq 1
then
  echo "El sistema es seguro"
else
  echo "El sistema es inseguro"
fi

---/ ej3.sh /---

Ahora veamos si estos dos ejemplos funcionan :)

------------------------------------------------------------------------------
|                                                                            |
|       $ chmod 755 ej1.sh                                                   |
|       $ ./ej1.sh                                                           |
|       Introduce el valor de A:                                             |
|       25                                                                   |
|       Introduce el valor de B:                                             |
|       23                                                                   |
|       Los numeros A y B son distintos                                      |
|         A es mayor que B                                                   |
|       $ ./ej1.sh                                                           |
|       Introduce el valor de A:                                             |
|       666                                                                  |
|       Introduce el valor de B:                                             |
|       666                                                                  |
|       Los numeros A y B son el mismo numero                                |
|       $ chmod 755 ej2.sh                                                   |
|       $ ./ej2.sh                                                           |
|       Introduce la cadena A:                                               |
|       hola                                                                 |
|       Introduce la codena B:                                               |
|       adios                                                                |
|       Las dos cadenas son distintas                                        |
|       $ ./ej2.sh                                                           |
|       Introduce la cadena A:                                               |
|       buh!                                                                 |
|       Introduce la codena B:                                               |
|       buh!                                                                 |
|       Las dos cadenas son iguales                                          |
|       $ ./ej2.sh                                                           |
|       Introduce la cadena A:                                               |
|                                                                            |
|       Introduce la codena B:                                               |
|       hax0rs                                                               |
|       La cadena A es una cadena nula                                       |
|       $ chmod 755 ej3.sh                                                   |
|       $ whoami                                                             |
|       ripe                                                                 |
|       $ ./ej3.sh                                                           |
|       Iniciando rutina de control de seguridad...                          |
|       El sistema es seguro                                                 |
|       $ su                                                                 |
|       Password:                                                            |
|       # ./ej3.sh                                                           |
|       Iniciando rutina de control de seguridad...                          |
|       El usuario root puede escribir en /etc/passwd                        |
|       El usuario root puede leer en /ets/shadow                            |
|       El sistema es inseguro                                               |
|       $                                                                    |
|                                                                            |
------------------------------------------------------------------------------

NOTA: Hay otra forma de realizar las coindiciones, y es utilizando los
      corchetes. Ejemplo:
        
                    if [ "$num1" -eq "$num2" ]
                    then
                    echo "jejej"
                    fi

            
Acabamos de ver los saltos condicionales con los que nos veremos a la hora de
programar en shell-script, y acto seguido veremos otra faceta importantisima
en el mundo de la programacion, los bucles, acciones que se repiten una y otra
vez mientras se cumpla una condicion determinada. Veamos como son estos en este
lenguaje interpretado.                           

Tenemos tres tipos de bucle, el primera que vamos a ver sera el 
"for-in-do-done". Su uso es el siguiente:

	for <variable>
	in <lista de valores>
	do
	<instrucciones>
	done

De manera que las intrucciones se ejecutaran una vez por cada valor en la lista 
de valores, asignando este a la variable especificada. Veamos un ejemplo.

---/ ej4.sh /---

#!/bin/sh
#
# Comprobacion rutinaria de la existencia de los ficheros necesarios para
# la ejecucion de una aplicacion.
#
for FILE
in ./lib/mysock.h ./lib/mynet.h ./lib/lang.h ./src/main.h 
do
  if test -r "$FILE"
  then
    echo "Comprobando $FILE .........[OK]"
  else
    echo "Comprobando $FILE .........[OK]"
    echo "La aplicacion no puede continuar"
    exit 0
  fi
done
echo "La aplicacion puede continuar"

---/ ej4.sh /---

Vemos que "for-in-do-done" es muy util en circumstancias como las que vemos en
el ejemplo, pero son muchas en las ocasiones en las que necesitamos que un 
bucle se repita mientras se da cierta circumstancia, y "for-in-do-done" no nos
permite realiza eso. Para ello existen "while-do-done" y "unlil-do-done", cuyos
usos son los que siguen:

	while [ condicion ]
        do
        <instrucciones>
        done

        until [ condicion ]
        do
        <instrucciones>
        done

En el primer caso las instrucciones entre "do" y "done" se ejecutaran 
repetidamente mientras la condicion sea cierta, mientras que en el segundo 
de los casos se ejecutara mientras sea falsa.

Bueno, ahora ya estas mas o menos preparado para entender un shell-script algo
mas complejo que los que hemos visto hasta ahora. Para ello os pongo algun
ejemplo comentado acto seguido.....

---/ prop.sh /---

#!/bin/sh
#
# Para ver las propiedades de una sesion en el sistema
#
echo "=-= 'date' =-="
echo "Shell                -> $SHELL"
echo "Usuario              -> $USER"
echo "Directorio home      -> $HOME"
echo "Directorio actual    -> 'pwd'"
echo "Nombre de la maquina -> $HOSTNAME"

---/ prop.sh /---

---/ block.sh /---

#!/bin/sh
#
# Bloquea un terminal, hasta que se introduzca la contrasea correcta.
#
trap "" 2 3 4			#   Para ignorar las seales
stty -echo			#   Evita que se pueda visualizar lo que
                                # el usuario introduce. Es para que no se
                                # vea la contrasea.
tput clear                      #   Limpia el contenido de la pantalla
tput cup 11 20                  #   Mueve el cursor
echo "Introduzca el password de desbloqueo"
tput cup 25 80
read PASS
tput clear                      #   Limpia el contenido de la pantalla
tput cup 12 24                  #   Mueve el cursor
echo "EL TERMINAL ESTA BLOQUEADO"
tput cup 25 80
INTR=                           #   Declara una variable vacia
until test "$PASS" = "$INTR"
do
  read INTR
done
stty echo			#   Restaura la visualizacion de la entrada
                                # de usuario.
exit 0

---/ block.sh /---

Bueno hasta aqui el curso de UNIX de 7a69.... espero que ahora sepais como
moveros por un UNIX :-)

NOTA: La programacion de scripts es mas amplia, por lo que es posible que se
      le dedique algun articulo, estad atentos....

*EOF*
